/*
boatchars table
Sets special parameters for a character's jetski support.
Note that you do not need to define this to spawn and ride the jetski, simply having JSKI sprites will do.
Parameters for characters are as follows:
Engine sound - Prevent the Jetski from playing its engine sounds by setting this to 1.
Jetski effects - Disable the Jetski's effects by setting this to 1.
Car mode - Enable the Jetski's car mode setting this to 1.
To use in your own mod, copy the format seen below.

if not boatchars
	rawset(_G, "boatchars", {})
end
boatchars["example"] = {1, 1, 0}
*/

if not boatchars
	rawset(_G, "boatchars", {})
end
boatchars["blaze"] = {0, 0, 0}
boatchars["marine"] = {0, 0, 0}

freeslot("MT_MARINEJETSKI",
"MT_MARINEJETSKI_SPAWNER",
"MT_BOATSPAWN_CHAOSEMERALD",
"MT_MARINE_JOJOKE", -- :O 
"MT_MARINE_JOJOKE_2", -- >:) 
"MT_MARINEJETSKI_OVERLAY", --layering bs
"SFX_JSKIID", --jetski idle
"SFX_JSKIMO", --jetski mount
"SFX_JSKIDM", --jetski dismount
"SFX_JSKIJM", --jetski jump
"SFX_JSKIM1", --jetski moving
"SFX_JSKIM2",
"SFX_JSKIM3",
"SFX_JSKIM4",
"SFX_JSKIM5",
"SFX_JSKIM6",
"SFX_JSKITK",
"SFX_MSTNDS",
"SFX_MSCHGR",
"SFX_MSBRST",
"SFX_MARMBL",
"SFX_MCHPOS",
"S_MARINEJETSKI",
"S_MARINE_CHAOSDRIP",
"S_MARINE_CHAOS_SPLOOSH",
"S_STEPONTHEGAS",
"S_CRIPPLEDEER",
"S_BOATTOKEN",
"S_JOJOMENACING",
"S_PLAY_JETSKIRIDE",
"S_MARINE_CHAOSRIDE",
"SPR2_JSKI",
"SPR_MNCG",
"SPR_GASG",
"SPR_BTKN",
"SPR_CDRP",
"SPR_CSPL",
"SPR_JESK"
)
local givetokens
sfxinfo[sfx_jskijm].caption = "Jetski Jumping"
sfxinfo[sfx_jskiid].caption = "Engine Idling"	
sfxinfo[sfx_jskimo].caption = "Jetski Starting"
sfxinfo[sfx_jskidm].caption = "Jetski Powering Down"
sfxinfo[sfx_jskim1].caption = "Engine Humming"	
sfxinfo[sfx_jskim2].caption = "Engine Humming"
sfxinfo[sfx_jskim3].caption = "Engine Humming"
sfxinfo[sfx_jskim4].caption = "Engine Humming"
sfxinfo[sfx_jskim5].caption = "Engine Humming"
sfxinfo[sfx_jskim6].caption = "Engine Humming"
sfxinfo[sfx_jskitk].caption = "Jetski Token Collected"
sfxinfo[sfx_mstnds].caption = "/"
sfxinfo[sfx_mschgr].caption = "/"
sfxinfo[sfx_msbrst].caption = "/"
sfxinfo[sfx_marmbl].caption = "/"
sfxinfo[sfx_mchpos].caption = "Taunt"

spr2defaults[SPR2_JSKI] = SPR2_RUN_
states[S_MARINEJETSKI] = {
	sprite = SPR_JESK,
	frame = A
}
states[S_STEPONTHEGAS] = {
	sprite = SPR_GASG,
	frame = A
}
states[S_BOATTOKEN] = {
	sprite = SPR_BTKN,
	frame = FF_ANIMATE|FF_FULLBRIGHT,
	var1 = 13,
	var2 = 2
}
states[S_JOJOMENACING] = {
	sprite = SPR_MNCG,
	frame = FF_FULLBRIGHT|FF_ANIMATE,
	var1 = 2,
	var2 = 2,
	duration = -1
}
states[S_MARINE_CHAOSDRIP] = {
	sprite = SPR_CDRP,
	frame = FF_FULLBRIGHT,
}
states[S_MARINE_CHAOS_SPLOOSH] = {
	sprite = SPR_CSPL,
	frame = FF_FULLBRIGHT|FF_ANIMATE,
	var1 = 11,
	var2 = 2,
	duration = -1
}
mobjinfo[MT_MARINE_JOJOKE] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	dispoffset = -3,
	deathsound = sfx_ncspec
}
mobjinfo[MT_MARINE_JOJOKE_2] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	dispoffset = 5,
	deathsound = sfx_ncspec
}
mobjinfo[MT_BOATSPAWN_CHAOSEMERALD] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_MARINEJETSKI] = {
	doomednum = -1,
	spawnstate = S_INVISIBLE,
	flags = MF_SOLID|MF_SPECIAL|MF_SLIDEME,
	radius = 35*FRACUNIT,
	height = 35*FRACUNIT,
	dispoffset = -3,
	deathsound = sfx_ncspec
}
mobjinfo[MT_MARINEJETSKI_OVERLAY] = {
	doomednum = -1,
	spawnstate = S_MARINEJETSKI,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_MARINEJETSKI_SPAWNER] = {
	doomednum = -1,
	spawnstate = S_INVISIBLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
freeslot(
"MT_JETSPLATSH",
"S_JETSPLATSH",
"S_JETSPLATSHSPAWNER_DEATH",
"MT_JETSPLATSHSPAWNER",
"S_JETSPLATSHSPAWNER",
"MT_JETSPLATSHTAIL",
"S_JETSPLATSHTAIL",
"SPR_SPL2"
)

local FRACUNIT = FRACUNIT
local FRACBITS = FRACBITS
local TICRATE = TICRATE

local rushchaos = CV_RegisterVar({
	name = "rushchaos",
	defaultvalue = "On",
	flags = CV_NETVAR|CV_CALL|CV_NOINIT,
	PossibleValue = CV_OnOff,
	func = function(cv)
		if cv.value
			print("You can now use RushChars' Chaos Emerald reward.")
		else
			print("You can no longer use RushChars' Chaos Emerald reward.")
		end
	end
})

addHook("MobjSpawn", function(actor)
	actor.flags2 = MF2_SPLAT
	actor.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	actor.spriteyscale = FRACUNIT/2
	P_CreateFloorSpriteSlope(actor)
	
	actor.tracer = P_SpawnMobj(actor.x,actor.y,actor.z, MT_JETSPLATSHTAIL)
	actor.tracer.flags2 = MF2_SPLAT
	actor.tracer.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	actor.tracer.spriteyscale = FRACUNIT
	P_CreateFloorSpriteSlope(actor.tracer)
end, MT_JETSPLATSH)


addHook("MobjMoveBlocked", function(actor)
	actor.tracer.state = S_NULL
	actor.state = S_NULL
end, MT_JETSPLATSH)

function A_JETSPLATSH(actor, var1, var2)
	if (actor.sp)
		actor.reactiontime = $-1
		if (actor.reactiontime <= 0) then
			P_RemoveMobj(actor.tracer)
			P_RemoveMobj(actor)
			return
		end
		
		local scalefactor = ((actor.info.reactiontime-actor.reactiontime)*FRACUNIT)/28
		local deltafactor = 8
		
		
		if actor.flags2&MF2_AMBUSH
			scalefactor = $*3/2
			deltafactor = $*3/2
		elseif not (actor.flags2&MF2_BOSSNOTRAP)
			actor.momx = cos(actor.angle)*18
			actor.momy = sin(actor.angle)*18
		end
		
		if actor.flags2&MF2_SLIDEPUSH
			scalefactor = $*2/3
			deltafactor = $*3/2
		end
		
		actor.frame = ($&~FF_TRANSMASK)|(min(max((actor.info.reactiontime-actor.reactiontime)/(actor.info.reactiontime/9), 1), 9)*FF_TRANS10)
		actor.tracer.frame = ($&~FF_TRANSMASK)|(actor.frame&FF_TRANSMASK)
		
		actor.spritexscale = scalefactor
		actor.floorspriteslope.o = {
			x = actor.x,
			y = actor.y,
			z = actor.z
		}
		actor.floorspriteslope.zdelta = (actor.reactiontime*FRACUNIT)/deltafactor
		actor.floorspriteslope.xydirection = actor.angle
		
		actor.tracer.spritexscale = scalefactor
		actor.tracer.floorspriteslope.o = {
			x = actor.x,
			y = actor.y,
			z = actor.z
		}
		actor.tracer.floorspriteslope.xydirection = actor.angle
		actor.tracer.floorspriteslope.zdelta = (actor.reactiontime*FRACUNIT)/-deltafactor
		P_TeleportMove(actor.tracer,
		actor.x,//+(cos(actor.angle)*-8),
		actor.y,//+(sin(actor.angle)*-8),
		actor.z)
		actor.tracer.angle = actor.angle
		actor.tracer.color = actor.color
		actor.tracer.colorized = actor.colorized
	else
		actor.reactiontime = $1-1
		if (actor.reactiontime == 0) then
		actor.tracer.state = S_NULL
			actor.state = S_NULL
			return
		end
		local scalefactor = ((16-actor.reactiontime)*FRACUNIT)/28
		actor.spritexscale = scalefactor
		actor.floorspriteslope.o = {
		x = actor.x,
		y = actor.y,
		z = actor.z
		}
		actor.floorspriteslope.zdelta = (actor.reactiontime*FRACUNIT)/10
		actor.floorspriteslope.xydirection = actor.angle
		
		actor.tracer.spritexscale = scalefactor
		actor.tracer.floorspriteslope.o = {
		x = actor.x,
		y = actor.y,
		z = actor.z
		}
		actor.tracer.floorspriteslope.xydirection = actor.angle
		actor.tracer.floorspriteslope.zdelta = (actor.reactiontime*FRACUNIT)/-10
		P_TeleportMove(actor.tracer,
		actor.x,//+(cos(actor.angle)*-8),
		actor.y,//+(sin(actor.angle)*-8),
		actor.z)
		actor.tracer.angle = actor.angle
		actor.momx = cos(actor.angle)*15
		actor.momy = sin(actor.angle)*15
		
	end
end

mobjinfo[MT_JETSPLATSHSPAWNER] = {
spawnstate = S_JETSPLATSHSPAWNER,
radius = 1*FRACUNIT,
height = 1*FRACUNIT,
dispoffset = 0,
flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY
}

states[S_JETSPLATSHSPAWNER] = {
sprite = SPR_NULL,
frame = A|TR_TRANS50,
tics = 2,
--action = A_MultiShot,
--var1 = (MT_JETSPLATSH<<16)+12,
--var2 = -8,
nextstate = S_JETSPLATSHSPAWNER_DEATH
}

states[S_JETSPLATSHSPAWNER_DEATH] = {
sprite = SPR_NULL,
frame = A|TR_TRANS50,
tics = 2,
action = A_MultiShot,
var1 = (MT_JETSPLATSH<<16)+12,
var2 = -8,
nextstate = S_NULL
}

mobjinfo[MT_JETSPLATSH] = {
spawnstate = S_JETSPLATSH,
reactiontime = 16,
speed = 10*FRACUNIT,
radius = 1*FRACUNIT,
height = 1*FRACUNIT,
damage = 3,
spawnhealth = 0,
dispoffset = 0,
flags = MF_NOCLIPTHING|MF_NOGRAVITY|MF_MISSILE|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT
}


states[S_JETSPLATSH] = {
sprite = SPR_SPL2,
frame = A|TR_TRANS50,
tics = 1,
action = A_JETSPLATSH,
nextstate = S_JETSPLATSH
}


--states[S_SPLISH2].action = A_MultiShot
--states[S_SPLISH2].var1 = (MT_JETSPLATSH<<16)+12
--states[S_SPLISH2].var2 = -8


mobjinfo[MT_JETSPLATSHTAIL] = {
spawnstate = S_JETSPLATSHTAIL,
reactiontime = 15,
speed = 10*FRACUNIT,
radius = 1*FRACUNIT,
height = 1*FRACUNIT,
damage = 3,
spawnhealth = 0,
dispoffset = 0,
flags = MF_NOCLIPTHING|MF_NOGRAVITY
}


states[S_JETSPLATSHTAIL] = {
sprite = SPR_SPL2,
frame = B|TR_TRANS50,
tics = 15,
action = None,
nextstate = S_JETSPLATSHTAIL
}

local emeraldcolor = {
[S_CEMG1] = SKINCOLOR_MINT,
[S_CEMG2] = SKINCOLOR_BUBBLEGUM,
[S_CEMG3] = SKINCOLOR_SAPPHIRE,
[S_CEMG4] = SKINCOLOR_SKY,
[S_CEMG5] = SKINCOLOR_ORANGE,
[S_CEMG6] = SKINCOLOR_SALMON,
[S_CEMG7] = SKINCOLOR_AETHER,
}
//boat tokens
addHook("MobjThinker", function(mo)
	if not (gametyperules & GTR_CAMPAIGN) return end
	if mo and mo.valid and mo.health and emeralds and All7Emeralds(emeralds)
		if mo.state != S_BOATTOKEN
			mo.state = S_BOATTOKEN
		end
		mo.angle = $+FixedAngle(5*FRACUNIT)
		--mo.momz = cos(FixedAngle(6*FRACUNIT)*leveltime)*-1
		if (rusheffects.value) and (P_RandomRange(0, 3) == 0)
			local spark = P_SpawnMobjFromMobj(mo, P_RandomRange(30, -30)*FRACUNIT, P_RandomRange(30, -30)*FRACUNIT, P_RandomRange(30, -30)*FRACUNIT, MT_BOXSPARKLE)
			spark.colorized = true
			if leveltime % 2 == 0
				spark.color = SKINCOLOR_COPPER
			else
				spark.color = SKINCOLOR_AETHER
			end
		end
	end
end, MT_TOKEN)
local zpos
hud.add(function(v)
    if consoleplayer and consoleplayer.boattokens and All7Emeralds(emeralds)
		if not multiplayer
			zpos = 180
		else
			zpos = 14
		end
		if token then zpos = $ - 16 end
		
		if gametyperules & GTR_CAMPAIGN --CBW
			--v.drawScaled(156*FRACUNIT, zpos*FRACUNIT, FRACUNIT-FRACUNIT/2, v.cachePatch("BTKN"..(leveltime/2%13)+1))
			v.drawScaled(155*FRACUNIT + FRACUNIT*2/3, zpos*FRACUNIT, FRACUNIT-FRACUNIT/2, v.cachePatch("BTOKN"))
			v.drawString(168, zpos-4, "-")
			v.drawString(180, zpos-4, tostring(consoleplayer.boattokens))
			
		end
		/*if consoleplayer.boattutorialthingamajig and consoleplayer.boattutorialthingamajig > 0
			v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP, "small-center")
			v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP, "small-center")
		end*/
    end
end, "scores")
hud.add(function(v)
    if consoleplayer 
		if consoleplayer.boattutorialthingamajig and consoleplayer.boattutorialthingamajig > 0
			local var = consoleplayer.boattutorialthingamajig
			if var > 30 //lach's gonna kill me when he sees this elseif spam
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP, "small-center")
			elseif var > 27
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_10TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_10TRANS, "small-center")
			elseif var > 24
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_20TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_20TRANS, "small-center")
			elseif var > 21
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_30TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_30TRANS, "small-center")
			elseif var > 18
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_40TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_40TRANS, "small-center")
			elseif var > 15
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_50TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_50TRANS, "small-center")
			elseif var > 12
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_60TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_60TRANS, "small-center")
			elseif var > 9
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_70TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_70TRANS, "small-center")
			elseif var > 6
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_80TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_80TRANS, "small-center")
			elseif var > 3
				v.drawString(160, 180+10, "Hold c2 to summon", V_AQUAMAP|V_90TRANS, "small-center")
				v.drawString(160, 180+14, "the SS Super-Marine!", V_AQUAMAP|V_90TRANS, "small-center")
			end
		end
    end
end, "game")

COM_AddCommand("vehicularmanslaughter", function(player, arg)
	local p = player
	if p and p.mo and p.mo.valid and p.mo.health
		if arg and arg == "\x64\x6F\x72\x69\x66\x74\x6F"
			if p.gasgasgas == nil
				p.gasgasgas = true
				CONS_Printf(p, "what.")
			elseif p.gasgasgas == true
				p.gasgasgas = false
				CONS_Printf(p, "...Well, glad that's over. Don't even think about trying that again.")
			else
				p.gasgasgas = true
				CONS_Printf(p, "What the hell is wrong with you???")				
			end
		else
			if not p.boatlockout
				if arg
					p.boatmpset = tonumber(arg)
					--print(p.boatmpset)
					--print(arg)
					p.CheckBoat = true
					p.boatlockout = true
				end
			elseif not CBW_Battle
				P_KillMobj(p.mo)
				print("Just what do you think you're doing, " .. p.name .. "?")
			end
		end
	end
end)
local token = "client/rush/extra.dat"
addHook("PlayerSpawn", function(p)
	if p and p.mo and p.mo.valid and p.mo.health
	and (p == consoleplayer or p == secondarydisplayplayer)
		local file = io.openlocal(token)--check for the file
		if file--do you actually have a file to read
		and gametyperules & GTR_CAMPAIGN --CBW
		and not p.boatlockout
			COM_BufInsertText(p, "vehicularmanslaughter \""..file:read("*n").."\"")
		end
	end
end)
addHook("TouchSpecial", function(t, tmt)
	if not (gametyperules & GTR_CAMPAIGN) return end
	if tmt and tmt.player and tmt.valid and emeralds and All7Emeralds(emeralds) --and boatchars[tmt.skin] == true
		givetokens = true
		S_StartSound(nil, sfx_jskitk)
		if not multiplayer
			tmt.player.continues = $+1
			P_KillMobj(t, tmt)
			return true
		end
	end
end, MT_TOKEN)
addHook("PostThinkFrame", function()
	for p in players.iterate
		if p and p.mo and p.mo.valid
			if givetokens
				p.boattokens = min($+1, 99)
				p.CheckBoat = true
				if P_IsValidSprite2(p.mo, SPR2_JSKI) and p.boattokens == 1 and not (p.shutupboatboy)
					p.boattutorialthingamajig = TICRATE*6
					p.shutupboatboy = true
				end
			end
			if p.boattutorialthingamajig and p.boattutorialthingamajig > 0
				p.boattutorialthingamajig = $-1
			end
			
			if p.CheckBoat
				p.CheckBoat = false
				
				if p == consoleplayer or p == secondarydisplayplayer
					local file = io.openlocal(token)--check for the file
					if file--do you actually have a file to read
						if givetokens or p.removetokens
							local file = io.openlocal(token, "w+")
							file:write(p.boattokens)
						end
						file:close()
						//we over now yey
						
					else--bitch where the file
						   --this makes a default if theres no file to read
						local createfile = io.openlocal(token, "w+")
						createfile:write("0")
						createfile:close()
					end
				end
				
				if p.boatmpset
					p.boattokens = p.boatmpset
					p.boatmpset = nil
				end
			end
				
			if (p.powers[pw_carry]) == 19 or p.mo.boat
				if not (p.mo.boat and p.mo.boat.valid)
				or not p.mo.health
					p.eoiudjgjfih = true
					p.mo.noboatmount = TICRATE*3
					p.mo.spriteyoffset = 0
					if p.mo.health
						p.mo.state = S_PLAY_FALL
					end
					p.mo.flags2 = $&~MF2_DONTDRAW
					p.mo.shadowscale = p.mo.storedshadowscale or $
					p.mo.storedshadowscale = nil
					if p.powers[pw_carry] == 19
						p.powers[pw_carry] = 0
						p.mo.tracer = nil
					end
					p.mo.rollangle = 0
					p.mo.boattilt = 0
					p.pflags = $ & ~PF_JUMPED & ~PF_DRILLING
					P_RestoreMusic(p)
					
					if (p.mo.boat and p.mo.boat.valid)
						P_TeleportMove(p.mo, p.mo.boat.x, p.mo.boat.y, p.mo.boat.z+p.mo.boat.height*2*P_MobjFlip(p.mo.boat))
						if p.mo.boat.overlay.frame == 2
							p.mo.boat.overlay.frame = 0
						elseif p.mo.boat.overlay.frame == 3
							p.mo.boat.overlay.frame = 1
						end
					
						p.mo.boat.overlay.flags2 = $&~MF2_DONTDRAW
						
						if p.mo.boat.gasgasgas
						or not (boatchars[p.mo.skin] and boatchars[p.mo.skin][1])
							S_StopSound(p.mo.boat)
							S_StartSound(p.mo.boat, sfx_jskidm)
						end
					
						p.mo.boat.rider = nil
					end
					p.mo.boat = nil
				elseif p.mo.boat.gasgasgas
					p.mo.flags2 = $|MF2_DONTDRAW
				elseif p.mo.boat.overlay.state == S_MARINE_CHAOSDRIP
					if p.mo.state != S_MARINE_CHAOSRIDE
						p.mo.state = S_MARINE_CHAOSRIDE
					end						
				elseif p.mo.state != S_PLAY_JETSKIRIDE
					p.mo.state = S_PLAY_JETSKIRIDE
				end
				
				if p.powers[pw_underwater]
					p.powers[pw_underwater] = underwatertics
				end
				
				p.pflags = $|PF_JUMPED|PF_DRILLING //katsy note: this allows wall breaking and prevents skin changing while on the boat
				
				if p.mo.state == S_PLAY_JETSKIRIDE
				or p.mo.state == S_MARINE_CHAOSRIDE
					if p.followmobj and p.followmobj.valid
						p.followmobj.state = S_INVISIBLE
					end
					
					local frame = p.mo.frame & FF_FRAMEMASK
					local animchange = TICRATE
					if p.mo.state != S_MARINE_CHAOSRIDE
						if FixedHypot(p.mo.momx, p.mo.momy) <= 14*p.mo.scale or FixedHypot(p.mo.momx, p.mo.momy) <= animchange*p.mo.scale and leveltime % 2 == 0   
							if frame == 0
								frame = 1
							elseif frame == 1
								frame = 0
							end
						elseif FixedHypot(p.mo.momx, p.mo.momy) > animchange*p.mo.scale and frame == 1
							frame = 0
						end
						if FixedHypot(p.mo.momx, p.mo.momy) > animchange*p.mo.scale and leveltime % 2 == 0 or FixedHypot(p.mo.momx, p.mo.momy) > 47*p.mo.scale
							if frame == 0
								frame = 2
							elseif frame == 2
								frame = 0
							end		
						elseif FixedHypot(p.mo.momx, p.mo.momy) < animchange*p.mo.scale and frame == 2
							frame = 0
						end
					else
						if FixedHypot(p.mo.momx, p.mo.momy) > animchange*p.mo.scale and leveltime % 2 == 0 or FixedHypot(p.mo.momx, p.mo.momy) > 47*p.mo.scale
							if frame == 0
								frame = 1
							elseif frame == 1
								frame = 0
							end		
						elseif FixedHypot(p.mo.momx, p.mo.momy) < animchange*p.mo.scale and frame == 2
							frame = 0
						end					
					end
					p.mo.frame = ($ &~ FF_FRAMEMASK) + frame
				end
			end
		end
	end
	givetokens = false
end)

local jojokenames = {
	["jojo"] = true,
	["jotaru"] = true,
	["qtaro"] = true,
	["jotaru kujo"] = true,
	["kujo jotaru"] = true,
	["star platinum"] = true,
	["marine biologist"] = true,
	["icezer"] = true,
}

local renderer = CV_FindVar("renderer")
local models = CV_FindVar("gr_models")
addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid and p.mo.health
		if (p.mo.noboatmount)
			p.mo.noboatmount = $-1
		end
		if (p.boatspawncooldown)
			p.boatspawncooldown = $-1
		end
		if (p.cmd.buttons & BT_CUSTOM2) and rushchaos.value and not (p.eoiudjgjfih)
		and (p.boattokens or p.mo.OwnedBoat) and not p.boatspawncooldown and not (p.powers[pw_carry])
		and All7Emeralds(emeralds) and P_IsValidSprite2(p.mo, SPR2_JSKI)
			local crashtestdummy = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.mo.angle, 120*FRACUNIT), P_ReturnThrustY(p.mo, p.mo.angle, 120*FRACUNIT), 24*FRACUNIT, MT_MARINEJETSKI)
			crashtestdummy.flags = $|MF_NOSECTOR
			if not P_TryMove(crashtestdummy, crashtestdummy.x, crashtestdummy.y, false) or not R_PointInSubsectorOrNil(crashtestdummy.x, crashtestdummy.y)
				pcall(P_RemoveMobj, crashtestdummy)
				p.boatspawncooldown = TICRATE
				return
			else
				pcall(P_RemoveMobj, crashtestdummy)
			end
			p.boatspawncooldown = TICRATE*3
			if p.mo.skin == "marine"
			and (jojokenames[string.lower(p.name)] or (Cosmetics
			and Cosmetics.Hats and p.cos_hat and Cosmetics.Hats[p.cos_hat]
			and Cosmetics.Hats[p.cos_hat].name == "Starpost Crusader"))
			and p.mo.state == S_MARINE_JOJOKE and (p.mo.frame & FF_FRAMEMASK) == 5
			and not (p.mo.marinejojoke and p.mo.marinejojoke.valid)
				local j = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_MARINE_JOJOKE)
				j.skin = "marine"
				j.lifetime = 1
				j.state = S_MARINE_JOJOKE_AURA
				if (p.solchar and p.solchar.istransformed)
					j.eflags = $|MFE_FORCESUPER
				end
				j.target = p.mo
				p.mo.marinejojoke = j
				S_StartSound(j, sfx_marmbl)
				S_StartSound(j.target, sfx_mstnds)
				local menacing = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_MARINE_JOJOKE_2)
				menacing.state = S_JOJOMENACING
				menacing.scale = p.mo.scale/2
				menacing.menacing = true
				menacing.lifetime = 1
				menacing.target = p.mo
			else
				local s = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.mo.angle, 120*FRACUNIT), P_ReturnThrustY(p.mo, p.mo.angle, 120*FRACUNIT), 24*FRACUNIT, MT_MARINEJETSKI_SPAWNER)
				s.target = p.mo
				s.angle = p.mo.angle
				if p.gasgasgas
					s.gasgasgas = true
				end
				for i = 1, 7
					local e = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_BOATSPAWN_CHAOSEMERALD)
					e.state = S_CEMG1+(i-1)
					e.ang = FixedAngle((360*FRACUNIT)/7)
					e.target = s
					e.scale = p.mo.scale/21
					e.destscale = p.mo.scale
					e.i = i
					P_TeleportMove(e, p.mo.x+P_ReturnThrustX(e, e.ang*i, 60*p.mo.scale), p.mo.y+P_ReturnThrustY(e, e.ang*i, 60*p.mo.scale), p.mo.z)
				end
			end
		end
		if (p.mo.ihaveseverebraindamage) and not (p.mo.boat and p.mo.boat.valid and p.mo.boat.health)
			p.mo.ihaveseverebraindamage = nil
			if (p.mo.OwnedBoat and p.mo.OwnedBoat.valid)
				P_TeleportMove(p.mo.OwnedBoat, p.mo.x, p.mo.y, p.mo.z)
			else
				local boat = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_MARINEJETSKI)
				boat.owner = p.mo
				boat.angle = p.mo.angle
				boat.oldplayerangle = p.mo.angle--+FixedAngle(180*FRACUNIT)
				boat.lifetime = 0
				local overlay = P_SpawnMobjFromMobj(boat, 0, 0, 0, MT_MARINEJETSKI_OVERLAY)
				boat.overlay = overlay
				overlay.trg = boat
				overlay.angle = p.mo.angle		
				p.mo.boat = boat
				boat.rider = p.mo
				p.mo.OwnedBoat = boat
			end
		end
		p.boattokens = $ or 0
			if (p.powers[pw_carry] == 19) and p.mo.boat.valid and p.mo.boat.health
				p.powers[pw_ignorelatch] = 1<<15
				local cameraToPlayerAngle
				local rotation
				cameraToPlayerAngle = R_PointToAngle2(camera.x + camera.momx, camera.y + camera.momy, p.mo.x, p.mo.y)
				rotation = ((cameraToPlayerAngle - p.mo.boat.angle + ANGLE_202h) >> 29) + 1 // this gives us the frame rotation number for an 8-angle frame, as written in source 
				if (p.mo.boattilt)
					local rammnt = 6
					if rotation == 5 or (models and models.value == 1 and renderer and renderer.value == 2)
						if p.mo.rollangle < p.mo.boattilt
							p.mo.rollangle = min(p.mo.boattilt, $+FixedAngle(rammnt*FRACUNIT))
						elseif p.mo.rollangle > p.mo.boattilt
							p.mo.rollangle = max(p.mo.boattilt, $-FixedAngle(rammnt*FRACUNIT))
						end
					elseif  rotation == 1
						if p.mo.rollangle > -p.mo.boattilt
							p.mo.rollangle = max(-p.mo.boattilt, $+FixedAngle(rammnt*-FRACUNIT))
						elseif p.mo.rollangle < -p.mo.boattilt
							p.mo.rollangle = min(-p.mo.boattilt, $-FixedAngle(rammnt*-FRACUNIT))
						end
					elseif rotation == 4 or rotation == 6
						if p.mo.rollangle < p.mo.boattilt/2
							p.mo.rollangle = min(p.mo.boattilt/2, $+FixedAngle(rammnt*FRACUNIT/2))
						elseif p.mo.rollangle > p.mo.boattilt/2
							p.mo.rollangle = max(p.mo.boattilt/2, $-FixedAngle(rammnt*FRACUNIT/2))
						end
					elseif rotation == 2 or rotation == 8
						if p.mo.rollangle > -p.mo.boattilt/2
							p.mo.rollangle = max(-p.mo.boattilt/2, $+FixedAngle(-5*FRACUNIT/2))
						elseif p.mo.rollangle < -p.mo.boattilt/2
							p.mo.rollangle = min(-p.mo.boattilt/2, $-FixedAngle(-5*FRACUNIT/2))
						end
					else
						p.mo.rollangle = 0
					end
				else
					p.mo.rollangle = 0
				end
			end
		p.eoiudjgjfih = (p.cmd.buttons & BT_CUSTOM2)
	end
end)
addHook("MobjThinker", function(mo)
	if (mo.target and mo.target.valid and mo.target.health
	and mo.target.state == S_MARINE_JOJOKE and rushchaos.value
	and mo.target.player and (mo.target.player.cmd.buttons & BT_CUSTOM2))
		mo.lifetime = $+1
		mo.spawnfade = $ or 8
		if mo.lifetime % 2 == 0
			mo.state = $
			mo.spawnfade = max(1, $-1)
		end
		mo.frame = ($ & FF_FRAMEMASK)|mo.spawnfade<<FF_TRANSSHIFT
		mo.frame = $|FF_FULLBRIGHT
		if (mo.lifetime == TICRATE*2)
			local drip = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_MARINE_JOJOKE_2)
			drip.state = S_MARINE_CHAOSDRIP
			S_StartSound(drip, sfx_mschgr)
			drip.scale = mo.scale/25
			drip.target = mo.target
			drip.spawner = mo
		end
		--mo.blendmode = AST_ADD
	else
		P_RemoveMobj(mo)
	end
end, MT_MARINE_JOJOKE)
addHook("MobjThinker", function(mo)
	if not (mo.menacing)
		if (mo.target and mo.target.valid and mo.target.health and rushchaos.value
		and mo.target.player and ((mo.target.player.cmd.buttons & BT_CUSTOM2)
		and mo.target.state == S_MARINE_JOJOKE or mo.state == S_MARINE_CHAOSRIDE))
			mo.lifetime = $ or 0
			mo.lifetime = $+1
			mo.invert = $ or 1
			mo.info.dispoffset = 420
			if (mo.scale <= mo.target.scale*3) and mo.state != S_MARINE_CHAOS_SPLOOSH
				if mo.lifetime % 15 == 0
					mo.invert = $*-1
				end
				if mo.invert == 1
					mo.scale = $+$/25
				else
					mo.scale = $+$/75
				end
			else
				if mo.state != S_MARINE_CHAOS_SPLOOSH
					mo.state = S_MARINE_CHAOS_SPLOOSH
					mo.scale = mo.target.scale*2
					S_StopSound(mo)
					S_StartSound(mo.target, sfx_msbrst)
					mo.fuse = 22
				end
				if (mo.fuse == 7)
					local boat = P_SpawnMobjFromMobj(mo.target, 0, 0, 0, MT_MARINEJETSKI)
					boat.owner = mo.target
					boat.angle = mo.target.angle
					boat.oldplayerangle = mo.target.angle--+FixedAngle(180*FRACUNIT)
					boat.lifetime = 0
					boat.riderc2down = true
					local overlay = P_SpawnMobjFromMobj(boat, 0, 0, 0, MT_MARINEJETSKI_OVERLAY)
					boat.overlay = overlay
					overlay.trg = boat
					overlay.angle = mo.target.angle	
					overlay.state = S_MARINE_CHAOSDRIP
					mo.target.boat = boat
					boat.rider = mo.target
					mo.target.OwnedBoat = boat
					if (mo.target.player.boattokens) //prevent negative boat tokens
						mo.target.player.boattokens = $-1
					end
					mo.target.player.CheckBoat = true
					mo.target.player.removetokens = true
					P_PlayJingleMusic(mo.target.player, "BCHAOS", nil, true, JT_OTHER)
					if mo.target.player == displayplayer
						P_FlashPal(mo.target.player, PAL_WHITE, 4)
					end
				end
			end
		else
			P_RemoveMobj(mo)
		end
	else
		if (mo.target and mo.target.valid and mo.target.health and rushchaos.value
		and mo.target.state == S_MARINE_JOJOKE
		and mo.target.player and (mo.target.player.cmd.buttons & BT_CUSTOM2))
			mo.startup = $ or 0
			mo.startup = $+1
			mo.flags2 = $|MF2_DONTDRAW
			if mo.startup > TICRATE-TICRATE/3
				mo.flags2 = $&~MF2_DONTDRAW
				mo.lifetime = $+1
				mo.spawnfade = $ or 8
				if mo.lifetime % 2 == 0
					mo.spawnfade = max(1, $-1)
					if (mo.frame & FF_FRAMEMASK) == 2
						mo.frame = 0
					else
						mo.frame = $+1
					end
				end
				mo.momz = FRACUNIT/4*P_MobjFlip(mo.target)
				mo.frame = ($ & FF_FRAMEMASK)|mo.spawnfade<<FF_TRANSSHIFT
				mo.frame = $|FF_FULLBRIGHT
				if mo.lifetime > TICRATE+TICRATE/2
					mo.momz = 0
				end
			end
		else
			P_RemoveMobj(mo)
		end	
	end
end, MT_MARINE_JOJOKE_2)
local function collZCheck(m,n) return m.z < n.z+n.height and m.z+m.height > n.z end
addHook("MobjMoveCollide", function(t, tmt)
	if not (t.valid) or not (tmt.valid) or (tmt.player)
		return nil
	end
	if (tmt.flags & MF_MONITOR) or (tmt.type == MT_MINECART)
		return false
	end
	if (tmt.type == MT_SALOONDOOR) or (tmt.type == MT_SALOONDOORCENTER)
		tmt.flags2 = $|MF2_AMBUSH
		return false
	end
	if (tmt.flags & MF_SPRING) and not t.justsprung and collZCheck(t, tmt)
		P_DoSpring(tmt, t)
		t.sprung = true
		t.justsprung = TICRATE/4
		if (t.eflags & MFE_UNDERWATER)
			t.momz = $+$/2+$/8 --hacky solution since i cant be assed to get the exact values
		end
		if tmt.info.damage != 0
			t.angle = tmt.angle
			if t.rider and t.rider.valid and t.rider.health
				t.rider.angle = tmt.angle
			end
		end
		return nil
	end
	if (tmt.type == MT_STEAM) and collZCheck(t, tmt)
		P_SetObjectMomZ(t, 20<<FRACBITS, false)
		return nil
	end
	if ((tmt.type == MT_SPIKE) or (tmt.type == MT_WALLSPIKE)) and collZCheck(t, tmt)
		P_KillMobj(tmt, t, t)
		return false
	end
end, MT_MARINEJETSKI)

addHook("TouchSpecial", function(t, tmt) //ride the boat
	if (t.flags & MF_NOSECTOR) return true end
	if tmt.player and not tmt.player.bot and not (t.rider) and not (tmt.noboatmount) and not (tmt.player.powers[pw_carry])
		if (t.overlay.state == S_MARINE_CHAOSDRIP) and tmt.skin != "marine" return end
		if P_IsValidSprite2(tmt, SPR2_JSKI) and not (tmt.player.quittime)
			t.flags = $|MF_NOBLOCKMAP
			t.rider = tmt
			tmt.boat = t
			if t.owner and t.owner.valid and t.owner.OwnedBoat
				t.owner.OwnedBoat = nil
			end
			tmt.OwnedBoat = t
			t.owner = tmt
			if t.gasgasgas
			or not (boatchars[tmt.skin] and boatchars[tmt.skin][1])
				S_StartSound(t, sfx_jskimo)
			end
			t.riderc2down = true
			P_TeleportMove(tmt, t.x, t.y, t.z+t.height*P_MobjFlip(t)/2)
			if t.gasgasgas
				P_PlayJingleMusic(tmt.player, "GASGAS", nil, true, JT_OTHER)
			elseif t.overlay.state == S_MARINE_CHAOSDRIP
				P_PlayJingleMusic(tmt.player, "BCHAOS", nil, true, JT_OTHER)
			else
				P_PlayJingleMusic(tmt.player, "WTRBKE", nil, true, JT_OTHER)
			end
		end
	end
	return true
end, MT_MARINEJETSKI)

mobjinfo[MT_DUSTDEVIL].flags = MF_SPECIAL|MF_NOGRAVITY
addHook("TouchSpecial", function(t, tmt)
	if not (tmt.boat) return true end
	P_SetObjectMomZ(tmt.boat, 20<<FRACBITS, false)
	return true
end, MT_DUSTDEVIL)

local function chainthrower(chain, boater)
	if not (boater.boat) return false end
	P_SetObjectMomZ(boater.boat, 40<<FRACBITS, false)
	return true
end

addHook("TouchSpecial", chainthrower, MT_SMALLGRABCHAIN)
addHook("TouchSpecial", chainthrower, MT_BIGGRABCHAIN)

local function GetFOFHeightsAt(fof, x, y)
	local top
	local bottom
	
	if fof.t_slope
		top = P_GetZAt(fof.t_slope, x, y)
	else
		top = fof.topheight
	end
	
	if fof.b_slope
		bottom = P_GetZAt(fof.b_slope, x, y)
	else
		bottom = fof.bottomheight
	end
	
	return top, bottom
end
local renderer = CV_FindVar("renderer")
local models = CV_FindVar("gr_models")
addHook("MobjRemoved", function(mo)
	if mo.overlay and mo.overlay.valid
		P_RemoveMobj(mo.overlay)
	end
end, MT_MARINEJETSKI)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		if not rushchaos.value
			S_StartSound(P_SpawnMobjFromMobj(mo,0,0,0,MT_EXPLODE), sfx_pop)
			P_RemoveMobj(mo)
			return
		end
		
		if mo.overlay and mo.overlay.valid and mo.overlay.health
			P_TeleportMove(mo.overlay, mo.x, mo.y, mo.z)
			mo.lifetime = $+1
			if mo.lifetime <= TICRATE/2
				mo.momz = 0
				mo.momx = 0
				mo.momy = 0
			end
			if (mo.waitpls)
				mo.waitpls = nil
				mo.momz = $*4
			end
			if (mo.doublemymomz)
				mo.waitpls = true
				mo.doublemymomz = nil
			end
			//floating on water
			mo.yourinlavalmoa = $ or 0
			if P_IsObjectInGoop(mo)
				mo.yourinlavalmoa = 3
			end
			if not (mo.gasgasgas
			or (mo.rider and mo.rider.valid and boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
			or (mo.yourinlavalmoa)-- or (P_IsObjectInGoop(mo))
				mo.yourinlavalmoa = max($-1, 0)
				if (mo.eflags & MFE_UNDERWATER) and not (mo.wasinwater) and (mo.standingslope) and P_IsObjectOnGround(mo)
					P_TeleportMove(mo, mo.x, mo.y, mo.watertop-16*mo.scale)
					mo.momz = -2*mo.scale*P_MobjFlip(mo)
				end
				if not (mo.allowjumpinwater) and not (mo.jumpdownlmao)
					if (mo.eflags & MFE_UNDERWATER)
						if (mo.watertop and mo.watertop-mo.z < 22*mo.scale) and (mo.momz < 6*mo.scale) and (mo.momz > -6*mo.scale)
							mo.onwater = true
							mo.momz = 0
						elseif (mo.eflags & MFE_VERTICALFLIP) --and (mo.momz >= -8*mo.scale)
							mo.z = $1-(mo.scale/2)
							mo.momz = $1-(mo.scale/2)
						else--if (mo.momz <= 8*mo.scale)
							mo.z = $1+(mo.scale/2)
							mo.momz = $1+(mo.scale/2)
							if (mo.eflags & MFE_TOUCHWATER)
								mo.momz = $1+mo.scale
							else
								mo.momz = $1+(mo.scale/2)
							end
						end
					elseif (mo.wasinwater) and not (mo.sprung) and not (mo.eflags & MFE_SPRUNG)
						if (mo.rider and mo.rider.valid and mo.rider.health)	
							mo.momz = $1/2
						else
							mo.momz = $1/4
						end
						--print("2")
					end	
				end
			end
			if P_IsObjectOnGround(mo) or (mo.eflags & MFE_JUSTHITFLOOR) and not (mo.eflags & MFE_SPRUNG)
				mo.sprung = false
			end
			if mo.justsprung then mo.justsprung = $ - 1 end
			if (mo.momz*P_MobjFlip(mo) <= 0)
				mo.allowjumpinwater = false
			end
				//set jetski to appropriate state
			if (mo.gasgasgas)
				if mo.overlay.state != S_STEPONTHEGAS
					mo.overlay.state = S_STEPONTHEGAS
				end
			elseif mo.overlay.state != S_MARINEJETSKI and mo.overlay.state != S_MARINE_CHAOSDRIP
				mo.overlay.state = S_MARINEJETSKI
			end
			//actual control stuff if it has a rider
			mo.overlay.shadowscale = FRACUNIT-FRACUNIT/4
			mo.overlay.scale = mo.scale
			if (mo.gasgasgas)
				mo.overlay.shadowscale = 0 --it looks really weird and inconsistent if it has any shadow at all
				//even though the sprite's already pretty big it needs to be even bigger
				mo.overlay.scale = mo.scale+mo.scale/6
			end
			mo.overlay.radius = mo.radius
			if (mo.rider and mo.rider.valid and mo.rider.health)
				if (mo.rider.flags2 & MF2_TWOD) or twodlevel
					mo.flags2 = $|MF2_TWOD
				else
					mo.flags2 = $&~MF2_TWOD
				end
				if P_MobjFlip(mo.rider) < 0
					mo.flags2 = $|MF2_OBJECTFLIP
					mo.eflags = $|MFE_VERTICALFLIP
				else
					mo.flags2 = $&~MF2_OBJECTFLIP
					mo.eflags = $&~MFE_VERTICALFLIP
				end
				mo.radius = mo.rider.radius
				mo.scale = mo.rider.scale
				mo.rider.storedshadowscale = $ or mo.rider.shadowscale
				mo.rider.shadowscale = 2*FRACUNIT-FRACUNIT/2
				--mo.shadowscale = 35*mo.scale-mo.rider.radius
				local p = (mo.rider.player)
				--mo.rider.flags = $|MF_NOCLIP|MF_NOCLIPHEIGHT
				mo.rider.tracer = mo
				P_ResetPlayer(p)
				p.skidtime = 1
				
				if R_PointToDist2(mo.x-mo.momx, mo.y-mo.momy,
				mo.rider.x-mo.rider.momx, mo.rider.y-mo.rider.momy) > mo.radius*INT8_MAX
					P_TeleportMove(mo, mo.rider.x, mo.rider.y, mo.rider.z)
					if P_MobjFlip(mo) < 0
						mo.z = $ + mo.rider.height - mo.height
					end
				else
					P_TeleportMove(mo.rider, mo.x, mo.y, mo.z)
					if P_MobjFlip(mo) < 0
						mo.rider.z = $ + mo.height - mo.rider.height
					end
				end
				
				local cam = (p == displayplayer and camera)
				or (p == secondarydisplayplayer and camera2)
				if cam
					cam.aiming = p.aiming - ANG2*2*P_MobjFlip(mo)
					cam.z = $ + 4*mo.scale*P_MobjFlip(mo)
					local angle = R_PointToAngle2(mo.x, mo.y, cam.x, cam.y)
					P_TryCameraMove(cam, cam.x + P_ReturnThrustX(mo, angle, mo.radius),
					cam.y + P_ReturnThrustY(mo, angle, mo.radius))
				end
				
				p.mo.momx = mo.momx
				p.mo.momy = mo.momy
				p.mo.momz = mo.momz
				
				//change object's angle for turning
				local inf = 9
				mo.rider.boattilt = 0
				if (p.cmd.sidemove != 0)
					mo.angle = $+FixedAngle((p.cmd.sidemove*-1/inf)*FRACUNIT)
					mo.rider.boattilt = FixedAngle((p.cmd.sidemove*-1/inf)*FRACUNIT*4)
					//Turning assist
					if P_IsObjectOnGround(mo) or (mo.onwater) or (mo.wasinwater)
					or (mo.eflags & MFE_UNDERWATER)
						local turnfactor = 16
						if (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
							turnfactor = 29
						end
						local turnfactor2 = turnfactor-1
						local turnspeed = FixedHypot(mo.momx, mo.momy)/turnfactor
						
						mo.momx = $*turnfactor2/turnfactor
						mo.momy = $*turnfactor2/turnfactor
						P_Thrust(mo, mo.angle, turnspeed)
					end
					mo.turning = true
				elseif not (p.pflags & PF_ANALOGMODE) and not (p.pflags & PF_SLIDING)
					if p.mo.angle != mo.oldplayerangle
						local diff = (p.mo.angle - mo.angle)
						local factor = 1
						if diff > FixedAngle(50*FRACUNIT/inf)
							diff = FixedAngle(50*FRACUNIT/inf)
						elseif diff < FixedAngle(-50*FRACUNIT/inf)
							diff = FixedAngle(-50*FRACUNIT/inf)
						end
						//Apply it!
						if diff
							if (diff > ANGLE_180)
								diff = InvAngle(InvAngle(diff)/factor)
							else
								diff = $/factor
							end
							
							mo.angle = $+diff
							mo.rider.boattilt = diff*4
						end
						if P_IsObjectOnGround(mo) or (mo.onwater) or (mo.wasinwater)
						or (mo.eflags & MFE_UNDERWATER)
							local turnfactor = 16
							if (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
								turnfactor = 29
							end
							local turnfactor2 = turnfactor-1
							local turnspeed = FixedHypot(mo.momx, mo.momy)/turnfactor
							
							mo.momx = $*turnfactor2/turnfactor
							mo.momy = $*turnfactor2/turnfactor
							P_Thrust(mo, mo.angle, turnspeed)
						end
					end
				end
				//Jumping
				if P_IsObjectOnGround(p.mo) or not (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
				and ((mo.onwater) or (mo.wasinwater) or (mo.eflags & MFE_UNDERWATER)) 
					mo.startjump = false
				end
				if (p.cmd.buttons & BT_JUMP) and not (mo.jumpdownlmao)
					if P_IsObjectOnGround(mo) or not (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
					and ((mo.onwater) or (mo.wasinwater))
						mo.startjump = true
						P_SetObjectMomZ(mo, 10*FRACUNIT, false) 
						S_StartSound(mo, sfx_jskijm)
						mo.allowjumpinwater = true
						P_ResetScore(p)
					end
				end
				if (mo.startjump) and not (p.cmd.buttons & BT_JUMP)
					if mo.momz*P_MobjFlip(mo) > 0
						mo.momz = $/2
					end
					mo.startjump = false
				end
				p.mo.angle = mo.angle	
				mo.jumpdownlmao = (p.cmd.buttons & BT_JUMP)
				mo.overlay.angle = mo.angle
				p.drawangle = mo.angle
				if mo.jskisoundtime == nil
					mo.jskisoundtime = 0
				end
				//Acceleration
				if (p.cmd.buttons & BT_SPIN)
					local s1 = 65
					local s2 = 115
					if (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3]))
						s1 = 49
						s2 = 100
					end
					
					local angle = mo.angle
					local reversal = false
					if (p.cmd.forwardmove < -35)
						angle = $ + ANGLE_180
						reversal = true
					end
					
					if reversal and abs(R_PointToAngle2(0,0,mo.momx,mo.momy) - mo.angle) > ANGLE_90
					and FixedHypot(mo.momx, mo.momy) > 8*mo.scale
						--nothing
					elseif not (P_IsObjectOnGround(p.mo)
					or ((not (mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3])))
					and p.mo.eflags & MFE_UNDERWATER))
						P_Thrust(mo, angle, max(FixedHypot(mo.momx, mo.momy)/s1, mo.scale))
						mo.accelerating = true
					else
						P_Thrust(mo, angle, max(FixedHypot(mo.momx, mo.momy)/s2, mo.scale))
						mo.accelerating = true
					end
				end
				//stuff's here, light
                local soundstable = {
                  [sfx_jskim1] = 4,
                  [sfx_jskim2] = 6,
                  [sfx_jskim3] = 4,
                  [sfx_jskim4] = 6,
                  [sfx_jskim5] = 5,
                  [sfx_jskim6] = 6,
                }
				local sound = sfx_jskim1+min(FixedHypot(mo.momx, mo.momy)/mo.scale, 50)/10
				if FixedHypot(mo.momx, mo.momy) >= mo.scale*5 and mo.jskisoundtime > 0
					mo.jskisoundtime = min($-1, soundstable[sound])
				else
					mo.jskisoundtime = soundstable[sound]
				end
				//Sounds
				if not mo.gasgasgas
				and boatchars[mo.rider.skin] and boatchars[mo.rider.skin][1]
					//Haha lol, sound is disabled
					
				elseif not S_SoundPlaying(mo, sfx_jskiid) and not S_SoundPlaying(mo, sfx_jskimo) and FixedHypot(mo.momx, mo.momy) < mo.scale*5
					S_StartSound(mo, sfx_jskiid)
				
				elseif FixedHypot(mo.momx, mo.momy) >= mo.scale*5
					S_StopSoundByID(mo, sfx_jskiid)
					S_StopSoundByID(mo, sfx_jskidm)
					S_StopSoundByID(mo, sfx_jskimo)
						
					if (mo.jskisoundtime % soundstable[sound] == soundstable[sound]-1)
					  S_StartSound(mo, sound)
					end
				end

				//deletus the boat if the overlay isn't the funny drift car
				if not (mo.gasgasgas)
					mo.overlay.flags2 = $|MF2_DONTDRAW
				end
				mo.rider.player.pflags = $|PF_JUMPSTASIS
				local animchange = TICRATE
				if mo.gasgasgas or (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][3])
					if mo.gasgasgas
						mo.rider.flags2 = $|MF2_DONTDRAW
						mo.rumble = $ or 1
						mo.wheelframe = $ or 1
						local animchange = 55
						if FixedHypot(mo.momx, mo.momy) < (animchange-animchange/3)*mo.scale or leveltime % 2 == 0
							mo.rumble = $*-1
						end
						if FixedHypot(mo.momx, mo.momy) > mo.scale*4
							mo.cutthatoutjesus = false
							if (FixedHypot(mo.momx, mo.momy) < 15*mo.scale and leveltime % 4 == 0) and not (mo.cutthatoutjesus)
								mo.wheelframe = $*-1
								mo.cutthatoutjesus = true
								--print(leveltime)
							end
							if (FixedHypot(mo.momx, mo.momy) < 23*mo.scale and leveltime % 3 == 0) and not (mo.cutthatoutjesus)
								mo.wheelframe = $*-1
								mo.cutthatoutjesus = true
								--print(leveltime)
							end
							if (FixedHypot(mo.momx, mo.momy) < 45*mo.scale and leveltime % 2 == 0) and not (mo.cutthatoutjesus)
								mo.wheelframe = $*-1
								mo.cutthatoutjesus = true
								--print(leveltime)
							end
							if (FixedHypot(mo.momx, mo.momy) >= 45*mo.scale) and not (mo.cutthatoutjesus)
								mo.wheelframe = $*-1
								mo.cutthatoutjesus = true
								--print(leveltime)
							end
						end
						--actual frame setting jfc
						if mo.wheelframe == 1
							if mo.rumble == 1
								mo.overlay.frame = 0
							elseif mo.rumble == -1
								mo.overlay.frame = 2
							end
						elseif mo.wheelframe == -1
							if mo.rumble == 1
								mo.overlay.frame = 1
							elseif mo.rumble == -1
								mo.overlay.frame = 3
							end
						end
					end
					mo.turningtimer = $ or 0
					if (mo.turning)
						mo.turningtimer = $+1
					else
						mo.turningtimer = 0
					end
					if (rusheffects.value)
					and (mo.gasgasgas or not (boatchars[mo.rider.skin] and boatchars[mo.rider.skin][2]))
						if ((FixedHypot(mo.momx, mo.momy) <= 30*mo.scale or (mo.turningtimer > 17)) or P_RandomRange(0, 12) == 1) and (mo.accelerating)
							if P_RandomRange(3, 0) == 1 and P_IsObjectOnGround(mo)
								local d1 = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo.angle, -50*FRACUNIT)+P_ReturnThrustX(mo, mo.angle+FixedAngle(90*FRACUNIT), 35*FRACUNIT), P_ReturnThrustY(mo, mo.angle*-1, 50*FRACUNIT)+P_ReturnThrustY(mo, mo.angle+FixedAngle(90*FRACUNIT), 35*FRACUNIT), 0, MT_SPINDUST)
								d1.scale = mo.scale
								d1.momx = mo.momx/3
								d1.momy = mo.momy/3
								local d2 = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo.angle, -50*FRACUNIT)+P_ReturnThrustX(mo, mo.angle-FixedAngle(90*FRACUNIT), 35*FRACUNIT), P_ReturnThrustY(mo, mo.angle*-1, 50*FRACUNIT)+P_ReturnThrustY(mo, mo.angle-FixedAngle(90*FRACUNIT), 35*FRACUNIT), 0, MT_SPINDUST)
								d2.scale = mo.scale
								d2.momx = mo.momx/3
								d2.momy = mo.momy/3
							end
						end
						--print(mo.turning)
						if (mo.accelerating) 
							if FixedHypot(mo.momx, mo.momy) >= 20*mo.scale and P_RandomRange(0, 9) == 1
							or FixedHypot(mo.momx, mo.momy) >= 50*mo.scale and P_RandomRange(0, 3) == 1
							or FixedHypot(mo.momx, mo.momy) >= 65*mo.scale
							or P_RandomRange(0, 14) == 1
								local s = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo.angle, -50*FRACUNIT)+P_ReturnThrustX(mo, mo.angle-FixedAngle(90*FRACUNIT), 23*FRACUNIT), P_ReturnThrustY(mo, mo.angle*-1, 50*FRACUNIT)+P_ReturnThrustY(mo, mo.angle-FixedAngle(90*FRACUNIT), 23*FRACUNIT), 5*FRACUNIT, MT_SMOKE)
								s.scale = mo.scale
							end
						end
					end
				end
				mo.turning = false
				if FixedHypot(mo.momx, mo.momy) > 60*mo.scale and not (mo.gasgasgas)
					local ghost = P_SpawnGhostMobj(p.mo)
					ghost.spritexoffset = p.mo.spritexoffset
					ghost.spriteyoffset = p.mo.spriteyoffset
					ghost.color = SKINCOLOR_VAPOR
					ghost.colorized = true
					ghost.boatflashyghost = true
					--ghost.blendmode = AST_ADD
					
					ghost.fuse = (FixedHypot(mo.momx, mo.momy)/mo.scale-60)/10+3
					--print("test")
				end
				if not (p.cmd.buttons & BT_CUSTOM2)
					mo.riderc2down = false
				end
				//Dismount
				if (p.cmd.buttons & BT_CUSTOM2) and not (mo.riderc2down) or (p.powers[pw_carry] and (p.powers[pw_carry] != 19)) or (p.quittime)
					P_TeleportMove(mo.rider, mo.x, mo.y, mo.z+mo.height*2*P_MobjFlip(mo))
					p.mo.tracer = nil
					if mo.overlay.frame == 2
						mo.overlay.frame = 0
					elseif mo.overlay.frame == 3
						mo.overlay.frame = 1
					end
					p.eoiudjgjfih = true
					p.mo.noboatmount = TICRATE*3
					mo.rider.spriteyoffset = 0
					if mo.rider.health
						p.mo.state = S_PLAY_FALL
					end
					mo.flags = $ & ~MF_NOBLOCKMAP
					mo.rider.flags2 = $&~MF2_DONTDRAW
					mo.rider.shadowscale = mo.rider.storedshadowscale
					mo.rider.storedshadowscale = nil
					if p.powers[pw_carry] == 19
						p.powers[pw_carry] = 0
					end
					--if mo.overlay.state == S_STEPONTHEGAS
						mo.overlay.flags2 = $&~MF2_DONTDRAW
					--end
					mo.rider.rollangle = 0
					mo.rider.boattilt = 0
					if mo.gasgasgas
					or not (boatchars[p.mo.skin] and boatchars[p.mo.skin][1])
						S_StopSound(mo)
						S_StartSound(mo, sfx_jskidm)
					end
					
					P_RestoreMusic(p)
					mo.rider = nil
					p.mo.boat = nil
				else
					p.powers[pw_carry] = 19
				end
			end

			ApplyWindMomentum(mo)
			//JETSPLATSHes 
			if (rusheffects.value) and not (mo.gasgasgas)
			and (not (mo.rider and mo.rider.valid and boatchars[mo.rider.skin])
			or (not boatchars[mo.rider.skin][2] and not boatchars[mo.rider.skin][3]))
				if FixedHypot(mo.momx, mo.momy) > mo.scale*3 and leveltime % 3 == 0 and (P_IsObjectOnGround(mo) or (mo.onwater))
					local iangle = ANGLE_247h while iangle <= ANGLE_112h
						local splish = P_SPMAngle(mo, MT_JETSPLATSH, mo.angle+iangle, 0, MF2_AMBUSH)
						if splish and splish.valid
							splish.momx = mo.momx/2+cos(splish.angle)*8
							splish.momy = mo.momy/2+sin(splish.angle)*8
							splish.reactiontime = $ - 2
							splish.sp = true
								
								//local thrust = mo.radius*2-max(mo.scale*36-player.speed, 0)*2/3
							P_TryMove(splish,
							splish.x+mo.momx,
							splish.y+mo.momy,
							false)
								
							if FixedHypot(mo.momx, mo.momy) < 10*mo.scale
								local thrust = FixedHypot(mo.momx, mo.momy)-10*mo.scale
								P_Thrust(splish,mo.angle,thrust)
								P_TryMove(splish,
								splish.x+mo.momx-P_ReturnThrustX(nil,mo.angle,thrust),
								splish.y+mo.momy-P_ReturnThrustY(nil,mo.angle,thrust),
								false)
							end
						end
						iangle = $ + ANGLE_45
					end
				end
				if (mo.eflags & MFE_JUSTHITFLOOR) or not (mo.eflags & MFE_UNDERWATER) and (mo.wasinwater) or (mo.eflags & MFE_UNDERWATER) and not (mo.wasinwater) or not (mo.wasrested) and (mo.onwater)
					if (mo.oldmomz and mo.oldmomz*P_MobjFlip(mo) < -7*mo.scale or mo.oldmomz*P_MobjFlip(mo) > 7*mo.scale)
						local s = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_JETSPLATSHSPAWNER)
						S_StartSound(mo, sfx_splish)
					end
				end
				//Bubbles.
				if FixedHypot(mo.momx, mo.momy) > mo.scale*5 and leveltime % 3 == 0
					local b = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo.angle+FixedAngle(180)*FRACUNIT, 5*FRACUNIT)+P_RandomRange(15, -15)*FRACUNIT, P_ReturnThrustY(mo, mo.angle+FixedAngle(180)*FRACUNIT, 5*FRACUNIT)+P_RandomRange(15, -15)*FRACUNIT, mo.height*P_MobjFlip(mo)/4, MT_MARINE_BUBBLE)
					b.state = S_MARINE_LARGE
					b.fuse = TICRATE*2
					b.color = SKINCOLOR_AQUAMARINE1+leveltime%5
					b.colorized = true
					b.scale = P_RandomRange(3,5)*mo.scale/4 
					P_InstaThrust(b, R_PointToAngle2(mo.x, mo.y, mo.x+mo.momx, mo.y+mo.momy), FixedHypot(mo.momx, mo.momy)/2)
					--P_TeleportMove(b, mo.x, mo.y, mo.z+b.height)
				end
			end
			//Wind
			if (rusheffects.value) and (FixedHypot(mo.momx, mo.momy) > 45*mo.scale)
			and (mo.gasgasgas or not (mo.rider and mo.rider.valid and boatchars[mo.rider.skin] and boatchars[mo.rider.skin][2]))
				if FixedHypot(mo.momx, mo.momy) > 60*mo.scale or leveltime % 5 == 0
					local blazewind = P_SpawnMobjFromMobj(mo, P_RandomRange(-50, 50)*FRACUNIT, P_RandomRange(-50, 50)*FRACUNIT, 10*mo.scale+P_RandomRange(0, 58)*FRACUNIT*P_MobjFlip(mo), MT_BLAZEBOOSTWIND)					
					blazewind.fuse = 20
					blazewind.angle = R_PointToAngle2(mo.x, mo.y, mo.x+mo.momx, mo.y+mo.momy)
					blazewind.color = SKINCOLOR_COBALT
					blazewind.scale = mo.scale*2+mo.scale/2
					blazewind.blendmode = AST_ADD
				end
			end
			//I reject your realit- I mean friction and substitute my own!
			mo.friction = FRACUNIT
			if FixedHypot(mo.momx, mo.momy) > 0
				if FixedHypot(mo.momx, mo.momy) >= 75*mo.scale
					P_Thrust(mo, R_PointToAngle2(mo.x+mo.momx, mo.y+mo.momy, mo.x, mo.y), FixedHypot(mo.momx, mo.momy)/72)
				elseif (mo.accelerating)
					P_Thrust(mo, R_PointToAngle2(mo.x+mo.momx, mo.y+mo.momy, mo.x, mo.y), FixedHypot(mo.momx, mo.momy)/80) 
				elseif P_IsObjectOnGround(mo) or mo.onwater
					P_Thrust(mo, R_PointToAngle2(mo.x+mo.momx, mo.y+mo.momy, mo.x, mo.y), FixedHypot(mo.momx, mo.momy)/35)
				end
			end
			
			--print(FixedHypot(mo.momx, mo.momy)/FRACUNIT)
			mo.wasrested = (mo.onwater)
			mo.wasinwater = (mo.eflags & MFE_UNDERWATER)
			mo.onwater = false
			mo.accelerating = false
			mo.oldmomz = mo.momz
			
		else --wtf did you do
			P_RemoveMobj(mo)
		end
	end
end, MT_MARINEJETSKI)

//chaos emerald effect for boat spawning
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		local i = mo.i
		if mo.target and mo.target.valid and mo.target.health
			if not (mo.lifetime)
				mo.lifetime = TICRATE*7+TICRATE/2
				mo.speedup = 0
				mo.target.killmeplease = 1
			end
			mo.speedup = $+1
			if not (mo.lifetime2)
				if mo.lifetime > TICRATE*3+TICRATE/2
					mo.lifetime = $-2
				end
				if mo.lifetime <= TICRATE*3+TICRATE/2
					mo.lifetime2 = 1
					--mo.lifetime2startup = 1
				end
				mo.ang = $+FixedAngle((FRACUNIT/8*mo.speedup)/i)
			else
				mo.lifetime2 = $+1
				if mo.lifetime2 < TICRATE+TICRATE/2
					mo.ang = $+FixedAngle((FRACUNIT/6*mo.speedup)/i)
				elseif mo.lifetime2 < TICRATE*2--+TICRATE/2
					mo.target.freeze = true
				else
					if not (mo.target.BoatHathBeenSpawned)
						if (mo.target.target.OwnedBoat and mo.target.target.OwnedBoat.valid)
							P_TeleportMove(mo.target.target.OwnedBoat, mo.target.x, mo.target.y, mo.target.z)
							mo.target.BoatHathBeenSpawned = true
							mo.target.target.player.CheckBoat = true
							mo.target.target.player.removetokens = false
						else
							mo.target.BoatHathBeenSpawned = true
							if (mo.target.target.player.boattokens) //prevent negative boat tokens
								mo.target.target.player.boattokens = $-1
							end
							mo.target.target.player.CheckBoat = true
							mo.target.target.player.removetokens = true
							local boat = P_SpawnMobjFromMobj(mo.target, 0, 0, 0, MT_MARINEJETSKI)
							boat.scale = mo.scale
							boat.owner = mo.target.target
							boat.angle = mo.target.angle
							boat.oldplayerangle = mo.target.target.angle+FixedAngle(180*FRACUNIT)
							boat.lifetime = 0
							local overlay = P_SpawnMobjFromMobj(boat, 0, 0, 0, MT_MARINEJETSKI_OVERLAY)
							boat.overlay = overlay
							overlay.trg = boat
							overlay.angle = mo.target.angle
							if mo.target.gasgasgas
								boat.gasgasgas = true
								overlay.state = S_STEPONTHEGAS
							end
							mo.target.target.OwnedBoat = boat
						end
						S_StartSound(mo.target, sfx_s3k9c)
					end
					mo.lifetime = min($+25, TICRATE*25)
					mo.target.momz = $+mo.scale/6
				end
			end
			local ghost = P_SpawnGhostMobj(mo)
			ghost.fuse = 3
			if P_MobjFlip(mo.target) == 1
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.ang*i, mo.lifetime/2*mo.target.scale), mo.target.y+P_ReturnThrustY(mo, mo.ang*i, mo.lifetime/2*mo.target.scale), mo.target.z+mo.target.height/2)
			else
				P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.ang*i, mo.lifetime/2*mo.target.scale), mo.target.y+P_ReturnThrustY(mo, mo.ang*i, mo.lifetime/2*mo.target.scale), mo.target.z+mo.target.height-mo.height-mo.target.height/2)
			end
			if (rusheffects.value) and (P_RandomRange(1, 4) == 1)
				local ass = P_SpawnMobjFromMobj(mo, P_RandomRange(30, -30)*FRACUNIT, P_RandomRange(30, -30)*FRACUNIT, P_RandomRange(30, -30)*FRACUNIT, MT_BOXSPARKLE)
				ass.colorized = true
				ass.color = emeraldcolor[mo.state]
				ass.frame = $ | FF_FULLBRIGHT
				if P_RandomRange(0, 2) != 0
					ass.scale = mo.scale
				else
					ass.scale = mo.scale - mo.scale/4
				end
			end
			--if mo.target.state == S_PLAY_SUPER_TRANS2
			--end
			if mo.lifetime == TICRATE*25
				P_SpawnGhostMobj(mo)
				P_RemoveMobj(mo)
			end
		else
			P_SpawnGhostMobj(mo)
			P_RemoveMobj(mo)
		end
	end
end, MT_BOATSPAWN_CHAOSEMERALD)

addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		if mo.target and mo.target.valid and mo.target.health and mo.target.player
			if not (mo.BoatHathBeenSpawned)
				if not (mo.freeze)
					mo.thokspawnlmao = $ or TICRATE*2
					mo.thokspawnlmao = max($-1, 1)
					if leveltime*2 % mo.thokspawnlmao/2 == 0
						local thok = P_SpawnMobjFromMobj(mo, P_RandomRange(15, -15)*FRACUNIT, P_RandomRange(15, -15)*FRACUNIT, P_RandomRange(15, -15)*FRACUNIT+8<<FRACBITS, MT_THOK)
						thok.fuse = TICRATE
						thok.scale = mo.scale/2
						thok.destscale = 2*mo.scale
						thok.color = emeraldcolor[S_CEMG1+P_RandomRange(0, 6)]
						thok.blendmode = AST_ADD
						thok.scalespeed = mo.scale/7
					end
					if not (mo.target.player.cmd.buttons & BT_CUSTOM2)
					or not rushchaos.value
						P_RemoveMobj(mo)
					end
				end
			elseif not (mo.NowsYourChanceToBeABigThok)
				for i = 1, 2
					local thok = P_SpawnMobjFromMobj(mo, 0, 0, -120*FRACUNIT, MT_THOK)
					thok.fuse = TICRATE*2
					thok.tics = TICRATE*2
					thok.scale = mo.scale*5
					thok.destscale = 0
					thok.color = SKINCOLOR_SUPERSILVER1
					thok.blendmode = AST_ADD
					thok.scalespeed = mo.scale/4
					thok.info.dispoffset = 5
					mo.NowsYourChanceToBeABigThok = true
				end
			end
		else
			P_RemoveMobj(mo)
		end
	end
end, MT_MARINEJETSKI_SPAWNER)

addHook("PlayerCanDamage", function(p)
	if p.mo and p.mo.valid and p.mo.health and p.mo.boat and p.mo.boat.valid
		return true
	end
end)
addHook("ShouldJingleContinue", function(player, musname)
    if musname != "wtrbke" or musname != "gasgas" or musname != "bchaos" return end
    if player.powers[pw_carry] == 19
        return true
    else
        return false
    end
end)

addHook("MusicChange", function(om, nm)
	if (gamestate != GS_LEVEL) return end
	if (consoleplayer) and (consoleplayer.mo) and (consoleplayer.mo.boat) and not (consoleplayer.exiting)
		local musname = "wtrbke"
		if (consoleplayer.mo.boat.gasgasgas)
			musname = "gasgas"
		elseif consoleplayer.mo.boat.overlay.state == S_MARINE_CHAOSDRIP
			musname = "bchaos"
		end
		if (nm == mapmusname) and not (consoleplayer.mo.noboatmount)
			return musname
		end
	end
end)

addHook("ShouldDamage", function(mo, inf, src, dmg, dmgt)
	if mo and mo.valid and mo.player
		if mo.boat and mo.boat.valid and mo.boat.health
			if (dmgt & DMG_DEATHMASK)
				pcall(P_RemoveMobj, mo.boat)
				return true
			end
			if inf and ((inf.type == MT_SPIKE) or (inf.type == MT_WALLSPIKE))
				return false
			end
			if not (inf or src) and (dmgt == DMG_FIRE or dmgt == DMG_WATER
			or P_IsObjectOnGround(mo) or P_IsObjectOnGround(mo.boat))
				if (dmgt == DMG_FIRE)
					mo.boat.yourinlavalmoa = 3
				end
				return false
			end
		end
	end
end, MT_PLAYER)

local shadowAdded = false
addHook("MapLoad", function()
	if shadowAdded
	or not AddBikeTvInteraction
		return
	end
	shadowAdded = true
	AddBikeTvInteraction("marine", function(m)
		m.ihaveseverebraindamage = true
	end)
	AddBikeTvInteraction("blaze", function(m)
		m.ihaveseverebraindamage = true
	end)
end)
